/** @jsxImportSource @emotion/react */
import {jsx, css, keyframes, Global, SerializedStyles} from "@emotion/react";
import * as React from "react";
import {forwardRef, MouseEventHandler} from "react";
import cx from "classnames";
import { useGesture, Bounds} from '@use-gesture/react';
import {  useSpring,  } from "@react-spring/web";
import {  animated } from '@react-spring/web';
import { safeBind } from "./Hooks/compose-bind";

// import {useMeasure} from "customize-easy-ui-component/esm/Hooks/use-measure";
// import {safeBind} from "customize-easy-ui-component/esm/Hooks/compose-bind";

import {useTheme} from "./Theme/Providers";
import {useWindowSize} from "./Hooks/use-window-size";
import {useFocusElement} from "./Hooks/use-focus-trap";
import {VisuallyHidden} from "./VisuallyHidden";
// import {Bounds} from "@use-gesture/core/src/types/config";
import { Text } from "./Text";



/**
 * Touchable is a low level component which implements
 * the useTouchable hook. It provides consistent hover and
 * active styles on desktop and mobile devices.
 */

export interface DragbleProps {
  disabled?: boolean;
  /** By default, a touchable element will only highlight after a short
   * delay to prevent unintended highlights when scrolling. This will
   * only effect touch devices. */
  delay?: number;
  /**
   * By default, a touchable element will have an expanded press area of 20px
   * on touch devices. This will only effect touch devices.
   */
  pressExpandPx?: number;
  /** Whether active presses should be terminated when scrolling occurs. Typically this should be true. */
  terminateOnScroll?: boolean;
  component?: React.ElementType<any>;
  //限制游走的区域          MutableRefObject<null>;
  bounds?:  Bounds | HTMLElement | { current: HTMLElement | null };
  [key: string]: any; // lame hack to allow component injection
}


/** 随意拽按的一个区域： Dragble ,限制走动范围区域ref[div.ref.getBounRects]
 * 点击触发还是放入内部嵌套的组件中做。
 */
export const Dragable =
    ({
        children,
        className = "",
        delay=30,
        pressExpandPx,
        terminateOnScroll = false,
        bounds,
        disabled = false,
        ref,
        ...other
    }:DragbleProps) => {
    const theme = useTheme();
    const isLink = other.to || other.href;
    //这两个完全不是一个含义， hover是鼠标点位置进 出来。     #当前有显示内容了。
    const [hover, setHover] = React.useState(false);
    // const { bind, hover, active } = useTouchable({
    //     onPress,
    //     disabled,
    //     delay,
    //     terminateOnScroll,
    //     pressExpandPx,
    //     behavior: isLink ? "link" : "button"
    // });
    function onHover(state : any) {
        if(disabled)    return;
        const { active, movement: [mx], direction: [xDir] , cancel, event, swipe,tap,
            last,  velocity: [vx, vy], canceled, } = state;
        // console.log("Hover:",state,"active",active,"canceled:",canceled,"离",Math.abs(mx));
        setHover(active);
    }
    function onDrag(state : any) {
        if(disabled)    return;
        const { active, axis, movement: [mx,], direction: [xDir,] , cancel, event, swipe:[swpx,],
            tap,first,last,  canceled, type,down, offset: [x, y] } = state;
        // console.log("拉按type",state,"active",active,"last:",last,"离hover",hover);
        api.start({ x, y })
        if(first)   setHover(true);
        else if(last) {
            // console.log("关闭吗",state,"active",active,"canceled:",canceled,"离hover",hover);
            setHover(false);
            //菜单DdMenu点击后:type正常结束"pointerup"， 若被子组件取消的 触摸屏下的是"lostpointercapture" type
            //if(tap && type==="pointerup" && onPress){  onPress(event);  }
        }
    }

    const [{ x, y }, api] = useSpring(() => ({ x: 0, y: 0 }))
    const bind = useGesture({
            onDrag: (state) => onDrag(state),
            //onPointerDown: ({ event, ...sharedState }) => console.log('React合成事件触发', event),
            onHover: (state) => onHover(state),
        },
        {
            //过滤掉Tap不会触发Drag消息。但是已经被onDrag拉动过后的就不算=又会触发Handler()。 而tapsThreshold是启动算普通Drag最少px距离Default=3;
            drag: {
                filterTaps: true,
                bounds: bounds,         //{top:0,bottom:0,left:0,right:0},
            },
            hover: { mouseOnly: false },
        }
    );

//{...(other as any)}
    return (
        <animated.div   ref={ref}
            className={cx("Touchable", className, {
                "Touchable--hover": 1,
                "Touchable--active": 2
            })}
            style={{
                x,
                y,
                touchAction: 'none',
            }}
            css={{
                background: hover? theme.colors.background.tint1 : undefined
            }}
            {...(safeBind( bind(), other)  as any)}
        >
          {children}
        </animated.div>
     );
};

/*
以下：例子
* */

const spin = keyframes`
  to { 
    transform: rotate(360deg); 
  }
`;

const sizeStyles = {
    xs: css({ width: "1rem", height: "1rem" }),
    sm: css({ width: "3rem", height: "3rem" }),
    md: css({ width: "5rem", height: "5rem" }),
    lg: css({ width: "8rem", height: "8rem" }),
    xl: css({ width: "12rem", height: "12rem" })
};

interface DragPinnerProps extends React.HTMLAttributes<HTMLDivElement> {
    /**延迟关闭执行 onRequestPress；    =0不会自己关闭执行。
     * delay这段时间内，也没办法点击页面按钮的,也要同步等待后端的应答返回来，用户才能继续操作。
     *  */
    delay?: number;
    size?: "xs" | "sm" | "md" | "lg" | "xl";
    /** Attempt to center the spinner in the parent element */
    center?: boolean;
    /** Use an optional label */
    label?: string;
    //要不要显示出来！
    doing: boolean;
    /**点击关闭 或者任意其它的回调处理  */
    onRequestPress: () => void;
    //限制游走的区域          MutableRefObject<null>;
    //内部直接限制
    bounds?: Bounds | HTMLElement | { current: HTMLElement | null };
}

/** 一个例子
 *防止背景滚动 https://www.it610.com/article/1294815963329404928.htm 需要对ref.Div的ontouchstart、ontouchmove两个都加上preventDefault();
 * */
export const DragablePinner= (
    {
        delay = 0,
        size = "md",
        center=true,
        label,
        doing=false,
        bounds,
        onRequestPress,
        ...other
    }:DragPinnerProps) => {
    const theme = useTheme();
    const {innerHeight, innerWidth,}= useWindowSize();
    //嵌入开始
    const ref = React.useRef<HTMLDivElement | null>(null);
    useFocusElement(ref, false);
    //初始位置，?可以保存位置信息到 localStorage(“”，{}):  ?非固定0,0位置：计算相对偏移区域？
    const [iconxy, setIconxy] = React.useState({x:0, y:0});
    const windowBouds={top:0-innerHeight!, bottom: 0, left:0-innerWidth!, right: 0};

//嵌入结束 :【严重问题】传入的onRequestClose是会变动的，正好定时器执行后onRequestClose必然变，所以加入依赖项后，这里相当于死循环，开了关关了又再开!!useEffect事实死循环?
    React.useEffect(() => {
        if(delay===0)    return;
        const timer= setTimeout(() => {
            onRequestPress();
        }, delay);

        return () => {
            clearTimeout(timer);
        };
    }, [onRequestPress, delay]);

    if(!doing)  return null;

    return (
        <React.Fragment>
            <Global
                styles={{
                    html: {
                        //overflowY: active? 'hidden' : undefined,
                    }
                }}
            />
            <Dragable className="DragPinner__IconTrgger"
                      bounds={bounds? bounds : windowBouds}
                      css={{
                          color: theme.colors.text.default,
                          textAlign: "center",
                          display: "inline-block",
                          margin: 'auto',
                          zIndex: theme.zIndices.waituntil,
                          position: 'fixed',       //'absolute', 跟随滚动
                          // top: `${iconxy.y}px`,
                          // left: `${iconxy.x}px`,
                          bottom: `${iconxy.y}px`,
                          right: `${iconxy.x}px`,
                      }}
                      {...safeBind(
                          {
                              onClick: (e: React.MouseEvent) => {
                                  //可以其它操作一起执行。
                                  onRequestPress();
                              },
                              onKeyDown: (e: React.KeyboardEvent) => {    //#实际没法捕捉到了?
                                  if (e.key === "Escape") {
                                      e.stopPropagation();
                                      onRequestPress();
                                  }
                              },
                          },
                          other
                      )}
            >
                <div
                    className="DragPinner__BoundRct"
                    ref={ref}
                    css={[
                        css`
                        display: inline-block;
                        vertical-align: text-bottom;
                        border: 0.15em solid currentColor;
                        border-right-color: transparent;
                        border-radius: 50%;
                        animation: ${spin} 0.75s linear infinite;
                      `,
                        sizeStyles[size]
                    ]}
                >
                </div>

                {label ? (
                    <Text
                        className="DragPinner__label"
                        wrap={false}
                        css={{ display: "block", marginTop: theme.spaces.sm }}
                        variant="subtitle"
                    >
                        {label}
                    </Text>
                ) : (
                    <VisuallyHidden>{"Loading"}</VisuallyHidden>
                )}
            </Dragable>
        </React.Fragment>
    );
};

